package com.ljb.utilslibrary.commUtils;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 专门访问和设置SharePreference的工具类, 保存和配置一些设置信息
 *
 * @author lijianbin
 */
public class SP {
    private static final String TAG = "SP";
    /**
     * 保存在手机里的文件名
     */
    private static final String FILE_NAME = "smart_inspector";

    private SP() {
    }

    /**
     * 保存数据,并设置有效时间,超过该时间范围,值无效
     * 比如有效期设置为1小时,表示1小时后过期
     *
     * @param context       上下文
     * @param key           键
     * @param value         值
     * @param effectiveTime 有效时间,单位是秒
     */
    public static void putEffective(Context context, String key, Object value, long effectiveTime) {
        putExpired(context, key, value, getTimestamp() + effectiveTime);
    }

    /**
     * 保存数据,带有过期时间,超过该时间点,值无效
     *
     * @param context     上下文
     * @param key         键
     * @param value       值
     * @param expiredTime 过期时间点的时间戳
     */
    public static void putExpired(Context context, String key, Object value, long expiredTime) {
        put(context, key + '_', expiredTime);
        put(context, key, value);
    }

    /**
     * 获取设置了有效时间或过期时间的值
     *
     * @param context      上下文
     * @param key          键
     * @param defaultValue 默认值
     * @return 超过了有效时间, 超过了过期时间点或没有该key均返回默认值
     */
    public static Object getEffectiveOrExpired(Context context, String key, Object defaultValue) {
        if (isExpired(context, key)) {
            remove(context, key);
            remove(context, key + '_');
            return defaultValue;
        }
        return get(context, key, defaultValue);
    }

    /**
     * 判断对应的key的值是否过期
     *
     * @param key
     * @return true表示已过期, 值不可用, false表示没有过期, 值可用
     */
    private static boolean isExpired(Context context, String key) {
        Long expiredTime = (Long) get(context, key + '_', 0L);
        return expiredTime != 0L && getTimestamp() > expiredTime;
    }

    /**
     * 保存数据的方法
     *
     * @param context 上下文
     * @param key     键
     * @param value   值
     */
    public static void put(Context context, String key, Object value) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();

        if (value instanceof String) {
            editor.putString(key, (String) value);
        } else if (value instanceof Integer) {
            editor.putInt(key, (Integer) value);
        } else if (value instanceof Boolean) {
            editor.putBoolean(key, (Boolean) value);
        } else if (value instanceof Float) {
            editor.putFloat(key, (Float) value);
        } else if (value instanceof Long) {
            editor.putLong(key, (Long) value);
        } else {
            editor.putString(key, value.toString());
        }

        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 获取数据
     *
     * @param context      上下文
     * @param key          键
     * @param defaultValue 默认值
     * @return key所对应的value
     */
    public static Object get(Context context, String key, Object defaultValue) {
        if (!contains(context, key)) {
            Log.i(TAG, "get: key=" + key + ",该键不存在");
            return defaultValue;
        }

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        if (defaultValue instanceof String) {
            return sp.getString(key, (String) defaultValue);
        } else if (defaultValue instanceof Integer) {
            return sp.getInt(key, (Integer) defaultValue);
        } else if (defaultValue instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultValue);
        } else if (defaultValue instanceof Float) {
            return sp.getFloat(key, (Float) defaultValue);
        } else if (defaultValue instanceof Long) {
            return sp.getLong(key, (Long) defaultValue);
        }

        return defaultValue;
    }

    /**
     * 移除某个key对应的值
     *
     * @param context 上下文
     * @param key     键
     */
    public static void remove(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 清除所有的数据
     *
     * @param context 上下文
     */
    public static void clear(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        SharedPreferencesCompat.apply(editor);
    }

    /**
     * 查询某个key是否已经存在
     *
     * @param context 上下文
     * @param key     键
     * @return 查询的结果
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        return sp.contains(key);
    }

    /**
     * 返回所有的键值对
     *
     * @param context 上下文
     * @return 所有的键值对
     */
    public static Map<String, ?> getAll(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
        return sp.getAll();
    }

    /**
     * 获取系统时间戳
     *
     * @return
     */
    private static long getTimestamp() {
        return System.currentTimeMillis() / 1000;
    }

    /**
     * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
     */
    private static class SharedPreferencesCompat {
        private static final Method sApplyMethod = findApplyMethod();

        /**
         * 反射查找apply方法
         *
         * @return 方法
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Method findApplyMethod() {
            try {
                Class clz = SharedPreferences.Editor.class;
                return clz.getMethod("apply");
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }

        /**
         * 如果找到,则使用apply执行,否则使用commit
         *
         * @param editor 编辑者
         */
        public static void apply(SharedPreferences.Editor editor) {
            try {
                if (sApplyMethod != null) {
                    sApplyMethod.invoke(editor);
                    return;
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            editor.commit();
        }
    }
}


















